package com.alibaba.citrus.ots.platform.enhance.facade.service.diff.activity;

import com.alibaba.acm.shaded.com.google.common.collect.Lists;
import com.alibaba.acm.shaded.com.google.common.collect.Maps;
import com.alibaba.acm.shaded.com.google.common.collect.Sets;
import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.annotation.ProcessInvoker;
import com.alibaba.citrus.ots.platform.enhance.facade.service.diff.activity.constant.ActivityFlowEnum;
import com.alibaba.citrus.ots.platform.enhance.facade.service.diff.common.constant.DiffResultStatus;
import com.alibaba.citrus.ots.platform.enhance.facade.service.diff.common.constant.DiffTypeEnum;
import com.alibaba.citrus.ots.platform.enhance.facade.service.diff.common.DiffCheckRequest;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.constant.DiffStrategyRouteDict;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.constant.SalesOrderLineDiffStandardFieldDict;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.dataParser.DataParserManager;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.router.DiffCheckProcessor;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.router.DiffStrategyRoute;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.activity.template.ActivityUseRecordRelationStandardTemplate;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.template.SalesOrderLineStandardTemplate;
import com.alibaba.citrus.ots.platform.enhance.functions.diff.common.template.StandardTemplateDiff;
import com.alibaba.citrus.ots.platform.enhance.repository.ActivityQueryRepository;
import com.alibaba.citrus.ots.platform.enhance.repository.DiffErrorRepository;
import com.alibaba.citrus.ots.platform.enhance.repository.SalesOrderLineQueryServiceRepository;
import com.alibaba.citrus.ots.platform.enhance.repository.model.diff.activity.QueryActivityUseRecordParam;
import com.alibaba.citrus.ots.platform.enhance.repository.model.diff.activity.QuerySalesOrderLineParam;
import com.alibaba.citrus.ots.platform.enhance.repository.model.diff.common.SalesOrderLineDTO;
import com.alibaba.citrus.ots.platform.enhance.repository.model.diff.common.DiffErrorDTO;
import com.alibaba.citrus.ots.platform.enhance.repository.model.diff.common.FieldLineDTO;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.otsforecastsales.domian.activityterm.model.ActivityTerm;
import com.epoch.app.otsplatformenhance.model.dto.ActivityDiffCheckRequest;
import com.epoch.app.otsplatformenhance.salesorderlinediffactivity.service.SalesOrderLineDiffActivityService;
import com.epoch.app.otspricecenter.model.enums.ActivityTypeEnum;
import com.epoch.app.otspricecenter.sdo.ActivityUseRecordRelationSDO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author hanguo
 * @date 2022/1/20
 * @Description 请填写描述信息
 */
@Service
@Primary
public class SalesOrderLineDiffCheckServiceImpl implements SalesOrderLineDiffActivityService {

    private Log log = Log.getLogger(SalesOrderLineDiffCheckServiceImpl.class);

    @Resource
    private ActivityQueryRepository activityQueryRepository;

    @Resource
    private DataParserManager dataParserManager;

    @Resource
    private StandardTemplateDiff standardTemplateDiff;

    @Resource
    private DiffStrategyRoute diffStrategyRoute;

    @Resource
    private SalesOrderLineQueryServiceRepository salesOrderLineQueryServiceRepository;

    @Resource
    private ApplicationContext applicationContext;

    @Resource
    private DiffErrorRepository diffErrorRepository;


    /**
     * 日志
     */

    @Override
    @FacadeInvoker
    public Result<String> activityOccupyDiffCheck(ActivityDiffCheckRequest request) {
        // 定时任务（ScheduleX ），扫描新增的销售子单。---》 DAO,按modify时间升序，可以支持分页查询 20。
        // 存到对账记录表中 --->暂时不做
        // 从销售子单中的提取数据和标准模板对比 ---》解决重和漏的问题 ---》
        // 根据活动id查询活动使用记录 ---》
        // 活动使用记录和活动使用记录的标准模板对比 ---》解决重和漏的问题 ---》
        // 把活动使用记录中的字段根据规则引擎生成表达式 b1 ---》
        // 把销售子单中的字段根据规则引擎生成表达式 b2 ---》
        // 对比b1 和 b2 --->解决错的问题 ---》

        QuerySalesOrderLineParam orderLineDTO = new QuerySalesOrderLineParam();
        orderLineDTO.setLimit(request.getLimit());
        orderLineDTO.setStatus(ActivityFlowEnum.ACTIVITY_OCCUPY.getStatus());
        orderLineDTO.setStart(request.getStart());
        orderLineDTO.setStartModifyTime(request.getStartDiffDate());
        orderLineDTO.setEndModifyTime(request.getEndDiffDate());
        Result<List<SalesOrderLineDTO>> listResult = salesOrderLineQueryServiceRepository.querySalesOrderLineByGmtModifyAsc(orderLineDTO);

        int total = listResult.getTotal();
        boolean isFirst = true;
        while (orderLineDTO.getStart() < total) {
            if (!isFirst) {
                listResult = salesOrderLineQueryServiceRepository.querySalesOrderLineByGmtModifyAsc(orderLineDTO);
            } else {
                isFirst = false;
            }
//            //同一销售子单多活动处理
//            dealMultiplyActivity(listResult);
            List<SalesOrderLineDTO> salesOrderLineDTOS = listResult.getResult();
            if (CollectionUtils.isNotEmpty(salesOrderLineDTOS)) {

                //特价活动过滤
                salesOrderLineDTOS = filterSpecialActivityData(salesOrderLineDTOS);

                if(CollectionUtils.isNotEmpty(salesOrderLineDTOS)){

                    List<DiffErrorDTO> diffErrorDTOList = new ArrayList<>();
                    for (SalesOrderLineDTO salesOrderLineDTO : salesOrderLineDTOS) {
                        DiffErrorDTO diffErrorDTO = applicationContext.getBean(SalesOrderLineDiffCheckServiceImpl.class)
                                .doDiff(salesOrderLineDTO);
                        if (Objects.nonNull(diffErrorDTO.getStatus())
                                && diffErrorDTO.getStatus().equals(DiffResultStatus.FAIL.getStatus())) {
                            diffErrorDTOList.add(diffErrorDTO);
                        }
                    }
                    //保存错误对账记录
                    if (CollectionUtils.isNotEmpty(diffErrorDTOList)) {
                        //批量保存差错记录
                        diffErrorRepository.batchSaveDiffErrorList(diffErrorDTOList);
                    }
                }

            }
            orderLineDTO.setStart(orderLineDTO.getStart() + orderLineDTO.getLimit());

        }

        return Result.success("true");
    }

    /**
     * 过滤出特价活动数据
     * @param salesOrderLineDTOS 销售单列表
     * @return
     */
    private List<SalesOrderLineDTO> filterSpecialActivityData(List<SalesOrderLineDTO> salesOrderLineDTOS) {

        List<SalesOrderLineDTO> result = Lists.newArrayList();

        //1.获取所有的活动项目号编码
        List<String> featuresList = salesOrderLineDTOS.stream()
                .map(SalesOrderLineDTO::getFeatures).collect(Collectors.toList());

        Set<String> activityTermIds = featuresList.stream()
                .map(e -> (String) JSONObject.parseObject(e).get("activityNumber")).collect(Collectors.toSet());

        //2.根据活动项目号编码查询活动号
        List<ActivityTerm> activityTerms = activityQueryRepository.queryActivityIdsByActivityTermIds(activityTermIds);
        if(CollectionUtils.isEmpty(activityTerms)){
            return result;
        }

        //3.根据活动号进行分组聚合
        Map<String, List<ActivityTerm>> activityMap = activityTerms.stream().collect(Collectors.groupingBy(ActivityTerm::getActivityId));


        //4.根据活动号过滤出特价活动的活动项目号
        Set<String> activityIds = activityMap.keySet();
        QueryActivityUseRecordParam request = new QueryActivityUseRecordParam();
        request.setActivityIds(new ArrayList<>(activityIds));
        request.setActivityType(ActivityTypeEnum.SPECIAL_OFFER_PRICE.getValue());
        Result<List<String>> filterActivityIdResult = activityQueryRepository.filterActivityIdsByActivityFacadeCode(request);
        if (CollectionUtils.isEmpty(filterActivityIdResult.getResult())) {
            return result;
        }

        //5.过滤出特价活动的销售子单
        List<String> specialPriceActivityIds = filterActivityIdResult.getResult();

        Set<String> specialPriceActivitySet = Sets.newHashSet();
        for (String activityId : activityMap.keySet()) {
            if(specialPriceActivityIds.contains(activityId)){
                List<ActivityTerm> activityTermTmp = activityMap.get(activityId);
                specialPriceActivitySet.addAll(activityTermTmp.stream().map(ActivityTerm::getActivityTermId).collect(Collectors.toSet()));
            }
        }


        List<SalesOrderLineDTO> salesOrderLineFilterDTOS = salesOrderLineDTOS.stream().filter(e -> specialPriceActivitySet
                .contains(JSONObject.parseObject(e.getFeatures()).get("activityNumber"))).collect(Collectors.toList());

        //6.对于activityCode = a1/a2 这种形式的数据处理
        salesOrderLineFilterDTOS.forEach(e -> {

            String activityCode = e.getActivityCode();
            if (activityCode.contains("/")) {
                String[] split = activityCode.split("/");
                for (String subActivityCode : split) {
                    String features = e.getFeatures();
                    if (StringUtils.isNotBlank(features)) {
                        String activityNumber = (String) JSONObject.parseObject(features).get("activityNumber");
                        if (activityNumber.startsWith(subActivityCode)) {
                            e.setActivityCode(subActivityCode);
                            break;
                        }
                    }

                }
            }

        });

        return salesOrderLineFilterDTOS;

    }

    /**
     * 处理一个销售子单对应多个活动的数据
     *
     * @param listResult
     */
//    private void dealMultiplyActivity(Result<List<SalesOrderLineDTO>> listResult) {
//        List<SalesOrderLineDTO> salesOrderLineDTOS = new ArrayList<>();
//        listResult.getResult().forEach(e -> {
//            String activityCode = e.getActivityCode();
//            if (activityCode.contains("/")) {
//                for (String subActivityCode : e.getActivityCode().split("/")) {
//                    SalesOrderLineDTO salesOrderLineDTO = new SalesOrderLineDTO();
//                    BeanUtils.copyProperties(e, salesOrderLineDTO);
//                    salesOrderLineDTO.setActivityCode(subActivityCode);
//                    salesOrderLineDTOS.add(salesOrderLineDTO);
//                }
//
//            } else {
//                salesOrderLineDTOS.add(e);
//            }
//        });
//
//        listResult.setResult(salesOrderLineDTOS);
//    }


    /**
     * 批量查询活动使用记录数据
     *
     * @param salesOrderLineDTO
     * @return
     */
    private Map<String, ActivityUseRecordRelationSDO> obtainActivityUseRecordDTOMap(SalesOrderLineDTO salesOrderLineDTO) {

        Map<String, ActivityUseRecordRelationSDO> resultMap = new HashMap<>();

        QueryActivityUseRecordParam queryActivityUseRecordParam = new QueryActivityUseRecordParam();
        queryActivityUseRecordParam.setStart(0);

        List<String> subOrderIds = new ArrayList<>();
        subOrderIds.add(salesOrderLineDTO.getFrontOrderLineId());

        queryActivityUseRecordParam.setLimit(subOrderIds.size());
        queryActivityUseRecordParam.setSubOrderIds(subOrderIds);
        //这里状态是否需要设置需要确认 todo...hanguo
//        queryActivityUseRecordDTO.setStatus(1);

        Result<List<ActivityUseRecordRelationSDO>> activityUseRecordRelationSDOs = activityQueryRepository.queryListByForecastSubOrderIds(queryActivityUseRecordParam);

        if (CollectionUtils.isEmpty(activityUseRecordRelationSDOs.getResult())) {
            return resultMap;
        }
        resultMap.putAll(
                activityUseRecordRelationSDOs.getResult().stream().collect(Collectors.toMap(
                        e ->e.getActivityTermId() + "_" + e.getSubOrderId() + "_" + e.getSequenceNo(),
                        Function.identity(), (x, y) -> x)));

        return resultMap;
    }

    @ProcessInvoker
    public DiffErrorDTO doDiff(SalesOrderLineDTO salesOrderLineDTO) {
        //批量查询活动使用记录
        Map<String, ActivityUseRecordRelationSDO> activityUseRecordDTOMap = obtainActivityUseRecordDTOMap(salesOrderLineDTO);

        //获取key
        String sequenceNo = null;
        String activityTermId = null;

        String features = salesOrderLineDTO.getFeatures();
        if(StringUtils.isNotBlank(features)){
            sequenceNo = (String) JSONObject.parseObject(salesOrderLineDTO.getFeatures()).get("sequenceNo");
            activityTermId = (String) JSONObject.parseObject(salesOrderLineDTO.getFeatures()).get("activityNumber");
        }
//
//        if(StringUtils.isBlank(sequenceNo) || StringUtils.isBlank(activityTermId)){
//
//        }

        //1. 获取活动使用记录数据
        ActivityUseRecordRelationSDO activityUseRecordRelationSDO = activityUseRecordDTOMap.get(activityTermId + "_"
                + salesOrderLineDTO.getFrontOrderLineId() + "_" + sequenceNo);
        try {
            //2. 数据抽取
            Map<String, FieldLineDTO> salesOrderLineDataMap = dataParserManager.parse(salesOrderLineDTO);
            //3. 和标准模板进行对比，检查是否缺的问题。 缺失有两个问题： a. 字段缺失， b. 数值缺失
            standardTemplateDiff.check(SalesOrderLineStandardTemplate.obtainTemplateFieldSet(),
                    salesOrderLineDataMap, null);
            //4. 从活动使用记录上抽取数据
            Map<String, FieldLineDTO> activityRecordDataMap = dataParserManager.parse(activityUseRecordRelationSDO);
            //5. 和标准模板进行对比，检查是否缺的问题。
            Result<String> checkResult = standardTemplateDiff.check(ActivityUseRecordRelationStandardTemplate.obtainTemplateFieldSet(), activityRecordDataMap, null);
            if (!checkResult.isSuccess()) {
                //埋点
                log.error("SalesOrderLineDiffCheckServiceImpl#salesOrderLineDiffCheck_fail");
                DiffErrorDTO diffErrorDto = buildDiffErrorDTO(salesOrderLineDTO, activityRecordDataMap,
                        salesOrderLineDataMap, checkResult.getMessage());
                return diffErrorDto;
            }
            //6. 对账
            DiffCheckRequest diffCheckRequest = buildDiffCheckRequest(salesOrderLineDataMap, activityRecordDataMap);
            DiffCheckProcessor diffCheckProcessor = diffStrategyRoute.obtainProcessor(diffCheckRequest);
            Result<String> diffResult = diffCheckProcessor.diff(diffCheckRequest);
            if (!diffResult.isSuccess()) {
                //埋点
                log.error("SalesOrderLineDiffCheckServiceImpl#salesOrderLineDiffCheck_fail");
                DiffErrorDTO diffErrorDto = buildDiffErrorDTO(salesOrderLineDTO, salesOrderLineDataMap,
                        activityRecordDataMap, diffResult.getMessage());
                return diffErrorDto;
            }
        } catch (Exception e) {
            //埋点
            log.error("SalesOrderLineDiffCheckServiceImpl#salesOrderLineDiffCheck_fail");
            log.error("对账出错了", e);
            DiffErrorDTO diffErrorDto = buildDiffErrorDTO(salesOrderLineDTO, null,
                    null, "对账出异常了！");
            return diffErrorDto;
        }
        return DiffErrorDTO.builder().build();

    }

    /**
     * 构造差错 DTO
     *
     * @param salesOrderLineDTO            销售子单
     * @param salesOrderLineDataMap        销售子单记录映射
     * @param activityRecordDataMap        活动使用记录映射
     * @param diffResult                   对账结果信息
     * @return 对账信息
     */
    private DiffErrorDTO buildDiffErrorDTO(SalesOrderLineDTO salesOrderLineDTO, Map<String, FieldLineDTO> salesOrderLineDataMap, Map<String, FieldLineDTO> activityRecordDataMap, String diffResult) {
        //1. 封装差错记录
        DiffErrorDTO diffErrorDto = DiffErrorDTO.builder()
                .diffType(DiffTypeEnum.SALES_ORDER_LINE_DIFF_ACTIVITY.getDiffType())
                //业务流程描述
                .diffDesc(DiffTypeEnum.SALES_ORDER_LINE_DIFF_ACTIVITY.getDiffDesc())
                //对账结果描述
                .result(diffResult)
                .diffData1(JSON.toJSONString(salesOrderLineDataMap))
                .diffData2(JSON.toJSONString(activityRecordDataMap))
                .strategyRoute(DiffStrategyRouteDict.SALES_ORDER_LINE_DIFF_ACTIVITY.getStrategyCode())
                //.mainOrderId(salesOrderLineDTO.getFrontOrderLineId())
                .subOrderId(salesOrderLineDTO.getFrontOrderLineId())
                .activityId(salesOrderLineDTO.getActivityCode())
                .activityTermId((String) JSONObject.parseObject(salesOrderLineDTO.getFeatures()).get("activityNumber"))
                .sequence((String) JSONObject.parseObject(salesOrderLineDTO.getFeatures()).get("sequenceNo"))
                .status(DiffResultStatus.FAIL.getStatus()).build();
        return diffErrorDto;
    }

    private DiffCheckRequest buildDiffCheckRequest(Map<String, FieldLineDTO> salesOrderLineDataMap, Map<String, FieldLineDTO> activityRecordDataMap) {
        DiffCheckRequest diffCheckRequest = new DiffCheckRequest();
        diffCheckRequest.setStrategyRoute(DiffStrategyRouteDict.SALES_ORDER_LINE_DIFF_ACTIVITY.getStrategyCode());
        diffCheckRequest.setDiffDesc(DiffTypeEnum.SALES_ORDER_LINE_DIFF_ACTIVITY.getDiffDesc());
        diffCheckRequest.setBaseLineDataMap(salesOrderLineDataMap);
        diffCheckRequest.setDiffDataMap(activityRecordDataMap);
        diffCheckRequest.setDiffType(DiffTypeEnum.SALES_ORDER_LINE_DIFF_ACTIVITY.getDiffType());

        //构建忽略列表，不比对这些标准字段
        Set<String> ignoreFieldSet = Sets.newHashSet();
        ignoreFieldSet.add(SalesOrderLineDiffStandardFieldDict.UNIT_PRICE.getFieldCode());
        ignoreFieldSet.add(SalesOrderLineDiffStandardFieldDict.SUB_TOTAL_AMOUNT.getFieldCode());
        ignoreFieldSet.add(SalesOrderLineDiffStandardFieldDict.SALE_UNIT.getFieldCode());
        ignoreFieldSet.add(SalesOrderLineDiffStandardFieldDict.REFUSE_REASON_CODE.getFieldCode());
        ignoreFieldSet.add(SalesOrderLineDiffStandardFieldDict.RETURN_FLAG.getFieldCode());
        //ignoreFieldSet.add(SalesOrderLineDiffStandardFieldDict.SPECIAL_OFFER_PRICE.getFieldCode());
        ignoreFieldSet.add(SalesOrderLineDiffStandardFieldDict.SAP_SALES_ORDER_LINE_ID.getFieldCode());

        diffCheckRequest.setIgnoreField(ignoreFieldSet);

        return diffCheckRequest;
    }
}
